package com.qiaofang.applet.service.other.service.impl;

import com.qiaofang.applet.common.base.MongoBaseService;
import com.qiaofang.applet.common.client.yxim.YxService;
import com.qiaofang.applet.common.client.yxim.YxUtil;
import com.qiaofang.applet.common.client.yxim.model.YxProperties;
import com.qiaofang.applet.common.client.yxim.model.YxResult;
import com.qiaofang.applet.common.client.yxim.model.YxUser;
import com.qiaofang.applet.common.context.QfContextHolder;
import com.qiaofang.applet.common.exception.BusinessException;
import com.qiaofang.applet.common.util.RedisKeyUtil;
import com.qiaofang.applet.common.util.RedisUtil;
import com.qiaofang.applet.constants.UserType;
import com.qiaofang.applet.service.member.domain.Employee;
import com.qiaofang.applet.service.member.domain.Member;
import com.qiaofang.applet.service.member.domain.MemberRemark;
import com.qiaofang.applet.service.member.repository.EmployeeRepository;
import com.qiaofang.applet.service.member.repository.MemberRepository;
import com.qiaofang.applet.service.other.domain.Corporation;
import com.qiaofang.applet.service.other.domain.YxImUser;
import com.qiaofang.applet.service.other.repository.YxImUserRepository;
import com.qiaofang.applet.service.other.service.CorporationService;
import com.qiaofang.applet.service.other.service.YxImUserService;
import com.qiaofang.applet.service.other.service.dto.AccidsQueryDto;
import com.qiaofang.applet.service.other.service.dto.YxImUserDTO;
import com.qiaofang.applet.service.other.service.dto.YxImUserReqDTO;
import com.qiaofang.applet.service.other.service.mapstruct.YxImUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.Id;
import org.springframework.data.domain.Example;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 网易云信im
 *
 * @author junze.liu
 */
@Slf4j
@Service
public class YxImUserServiceImpl extends MongoBaseService<YxImUser, String> implements YxImUserService {

    private final YxImUserRepository repository;

    @Autowired
    private YxImUserMapper yxImUserMapper;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private YxService yxService;

    @Autowired
    private EmployeeRepository employeeRepository;

    @Autowired
    private MemberRepository memberRepository;

    @Autowired
    private CorporationService corporationService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    public YxImUserServiceImpl(YxImUserRepository repository) {
        super(repository);
        this.repository = repository;
    }

    @Override
    public YxImUserDTO createYxIm(YxImUserReqDTO reqDTO, YxProperties config) {
        String corporationCode = "";
        String userId = reqDTO.getUserId();
        YxUser yxUser = new YxUser();
        if (UserType.MINI_PROGRAM.getCode().equals(reqDTO.getUserType())) {
            //小程序用户，查询会员表
            Member member = mongoTemplate.findById(userId, Member.class);
            if (member == null) {
                log.error("创建云信im失败，未获取到会员信息");
                throw new BusinessException("创建云信im失败，未获取到会员信息");
            }
            corporationCode = member.getCorporationCode();
            //设置会员姓名
            yxUser.setName(member.getName());
        } else if (UserType.EMPLOYEE.getCode().equals(reqDTO.getUserType())) {
            //app用户，查询经纪人表
            Employee employee = employeeRepository.findByEmployeeUniqueUuid(userId);
            if (employee == null) {
                log.error("创建云信im失败，未获取到经纪人信息");
                throw new BusinessException("创建云信im失败，未获取到经纪人信息");
            }
            corporationCode = employee.getCorporationCode();
            //设置经纪人姓名
            yxUser.setName(employee.getEmployeeName());
        }
        //生成accid
        //获取accid前缀
        Corporation corporation = corporationService.getCorporationByCorporationCode(corporationCode);
        //生成sccid
        yxUser.setAccid(YxUtil.generateAccid(corporation.getAccidPrefix()));
        //调用网易云信接口创建accid
        YxResult yxResult = yxService.createAction(yxUser, config);
        if (yxResult == null) {
            log.error("调用网易云信接口，创建accid失败");
            throw new BusinessException("调用网易云信接口，创建accid失败");
        }
        yxUser = yxResult.getInfo();
        //保存im用户信息
        YxImUser yxImUser = new YxImUser();
        yxImUser.setCorporationCode(corporationCode);
        yxImUser.setUserType(reqDTO.getUserType());
        yxImUser.setUserId(userId);
        yxImUser.setAccid(yxUser.getAccid());
        yxImUser.setName(yxUser.getName());
        yxImUser.setToken(yxUser.getToken());
        yxImUser.setCreateTime(new Date());
        repository.insert(yxImUser);
        redisUtil.set(RedisKeyUtil.getYxUserKey(yxUser.getAccid()), userId + ":" + reqDTO.getUserType());
        return yxImUserMapper.toDto(yxImUser);
    }

    @Override
    public YxImUserDTO getYxImUserByDto(YxImUserReqDTO reqDTO) {
        String userType = reqDTO.getUserType();
        String userId = reqDTO.getUserId();
        Criteria criteria = Criteria.where("userId").is(userId);
        criteria.and("userType").is(userType);
        YxImUser entity = mongoTemplate.findOne(new Query().addCriteria(criteria), YxImUser.class);
        if (entity == null) {
            return null;
        }
        YxImUserDTO yxImUserDTO = yxImUserMapper.toDto(entity);
        if ("1".equals(userType)){
            Optional<Member> optional = memberRepository.findById(userId);
            if (optional.isPresent()){
                Member member = optional.get();
                yxImUserDTO.setIcon(member.getHeadPortrait());
                yxImUserDTO.setName(member.getName());
            }
        }else {
            Employee employee = employeeRepository.findByEmployeeUniqueUuid(userId);
            if (employee != null){
                yxImUserDTO.setIcon(employee.getPhotoUrl());
                yxImUserDTO.setName(employee.getEmployeeName());
            }
        }
        return yxImUserDTO;
    }

    @Override
    public String getYxImUserIdAndType(String accid) {
        Object obj = redisUtil.get(RedisKeyUtil.getYxUserKey(accid));
        if (obj != null) {
            return (String) obj;
        }
        Optional<YxImUser> optional = findOne(Example.of(YxImUser.builder().accid(accid).build()));
        if (optional.isPresent()) {
            String str = optional.get().getUserId() + ":" + optional.get().getUserType();
            redisUtil.set(RedisKeyUtil.getYxUserKey(accid), str);
            return str;
        }
        return "";
    }

    @Override
    public YxImUser findByAccidAndUserType(String accid, String userType) {
        return repository.findFirstByAccidAndUserTypeAndCorporationCode(accid, userType, QfContextHolder.getContext().getCorporationCode());
    }

    @Override
    public void memberToEmp(String memberId, String employeeUniqueUuid) {
        Criteria criteriaEmp = Criteria.where("userId").is(employeeUniqueUuid)
                .and("userType").is("2");
        if (mongoTemplate.count(new Query(criteriaEmp), YxImUser.class) > 0){
            return;
        }
        Criteria criteriaMember = Criteria.where("userId").is(memberId)
                .and("userType").is("1");
        YxImUser yxImUser = mongoTemplate.findOne(new Query(criteriaMember), YxImUser.class);
        if (yxImUser == null){
            return;
        }
        String accid = yxImUser.getAccid();
        Update update = new Update();
        update.set("userId", employeeUniqueUuid);
        update.set("userType", "2");
        update.set("updateTime", new Date());
        mongoTemplate.updateFirst(new Query(Criteria.where("accid").is(accid)), update, YxImUser.class);
        redisUtil.set(RedisKeyUtil.getYxUserKey(accid), employeeUniqueUuid + ":2");
    }

    @Override
    public void empToMember(String memberId, String employeeUniqueUuid) {
        Criteria criteriaMember = Criteria.where("userId").is(memberId)
                .and("userType").is("1");
        if (mongoTemplate.count(new Query(criteriaMember), YxImUser.class) > 0){
            return;
        }
        Criteria criteriaEmp = Criteria.where("userId").is(employeeUniqueUuid)
                .and("userType").is("2");
        YxImUser yxImUser = mongoTemplate.findOne(new Query(criteriaEmp), YxImUser.class);
        if (yxImUser == null){
            return;
        }
        String accid = yxImUser.getAccid();
        Update update = new Update();
        update.set("userId", memberId);
        update.set("userType", "1");
        update.set("updateTime", new Date());
        mongoTemplate.updateFirst(new Query(Criteria.where("accid").is(accid)), update, YxImUser.class);
        redisUtil.set(RedisKeyUtil.getYxUserKey(accid), memberId + ":1");
    }

    @Override
    public List<YxImUserDTO> getYxUserInfoList(AccidsQueryDto accidsQueryDto) {
        List<String> accidList = accidsQueryDto.getAccidList();

        if (CollectionUtils.isEmpty(accidList)){
            return new LinkedList<>();
        }
        List<YxImUser> yxImUsers = repository.findListByAccidIn(accidList);
        if (CollectionUtils.isEmpty(yxImUsers)){
            return new LinkedList<>();
        }
        List<String> memberIds = new LinkedList<>();
        List<String> employeeUniqueUuids = new LinkedList<>();
        for (YxImUser yxImUser : yxImUsers) {
            String userId = yxImUser.getUserId();
            String userType = yxImUser.getUserType();
            if ("1".equals(userType)){
                memberIds.add(userId);
            }else {
                employeeUniqueUuids.add(userId);
            }
        }
        List<Member> members = new LinkedList<>();
        if (memberIds.size() > 0) {
            members = memberRepository.findListByIdIn(memberIds);
        }
        List<Employee> employees = new LinkedList<>();
        if (employeeUniqueUuids.size() > 0) {
            employees = employeeRepository.findListByEmployeeUniqueUuidIn(employeeUniqueUuids);
        }
        Map<String, YxImUser> yxImUserMap = yxImUsers.stream().collect(Collectors.toMap(YxImUser::getAccid, a -> a, (k1, k2) -> k1));
        Map<String, Member> memberMap = members.stream().collect(Collectors.toMap(Member::getId, a -> a, (k1, k2) -> k1));
        Map<String, Employee> employeeMap = employees.stream().collect(Collectors.toMap(Employee::getEmployeeUniqueUuid, a -> a, (k1, k2) -> k1));

        //获取该经纪人的所有客户备注，供后续组装参数
        Map<String, String> remarkMap = new HashMap<>();
        String employeeUniqueUuid = accidsQueryDto.getEmployeeUniqueUuid();
        if (StringUtils.isNotBlank(employeeUniqueUuid)) {
            Employee employee = employeeRepository.findByEmployeeUniqueUuid(employeeUniqueUuid);
            if (employee == null) {
                throw new BusinessException("经纪人不存在");
            }
            List<MemberRemark> remarkList = employee.getRemarkList();
            if (!CollectionUtils.isEmpty(remarkList)) {
                remarkMap = remarkList.stream().collect(Collectors.toMap(MemberRemark::getMemberId, MemberRemark::getRemark, (k1, k2) -> k1));
            }
        }

        List<YxImUserDTO> resultList = new ArrayList<>(accidList.size());
        for (String accid : accidList) {
            YxImUser yxImUser = yxImUserMap.get(accid);
            String userType = "";
            String userId = "";
            String token = "";
            if (yxImUser != null) {
                userType = yxImUser.getUserType();
                userId = yxImUser.getUserId();
                token = yxImUser.getToken();
            }
            String name = "";
            String icon = "";
            if ("1".equals(userType)){
                Member member = memberMap.get(userId);
                if (member != null) {
                    String remark = "";
                    if (!remarkMap.isEmpty()) {
                        remark = remarkMap.get(userId);
                    }
                    name = StringUtils.isNotEmpty(remark) ? remark : member.getName();
                    icon = member.getHeadPortrait();
                }
            }else {
                Employee emp = employeeMap.get(userId);
                if (emp != null) {
                    name = emp.getEmployeeName();
                    icon = emp.getPhotoUrl();
                }
            }
            resultList.add(YxImUserDTO.builder()
                    .accid(accid)
                    .token(token)
                    .userId(userId)
                    .userType(userType)
                    .icon(icon)
                    .name(name)
                    .build());
        }
        return resultList;
    }
}
